local Cross = require('ui.cross')
local Class = require('lib.hump.class')
local lume = require('lib.lume')
local flux = require('lib.flux')
local Timer = require('lib.timer')

return Class {
   _name = "Actor",
   
   init = function (
	 self, x, y, 
	 image, quad, scale, speed, def, atk, 
	 friendly, passable_tiles, range)
      self.x, self.y = x, y
      self.range = range and range * 8 or 45
      self.view_range = self.range * 2
      self.image, self.quad = image, quad
      self.scale = scale or 1
      self.visible = friendly and true
      self.speed, self.def, self.atk = speed, def, atk
      self.friendly = friendly or nil
      self.direction = 0
      self.velocity = 0
      self.fire_cooldown = 3
      self.can_fire = true
      self.rot = 0
      self.fuel = 100
      self.health = 100
      self.friction = .002
      self.show = true
      self.timers = {}
      if self.speed then
	 self.passable_tiles = passable_tiles
	 self.path = _src("path")(self.passable_tiles)
	 self.can_move = true
      end
      Timer.every(.5, 
		  function ()
		     self:think()
      end):group(self.timers)
   end,

   update = function (self, dt)
      flux.update(dt)
      Timer.update(dt, self.timers)
      self.thinking = nil
      if self.health <= 0 then lume.remove(Game.actors, self) end
   end,
   
   draw = function (self)
      if not self.visible then return end
      if self.is_moving then
	 local tx, ty = self.move_pos[1], self.move_pos[2]
	 Game.current_screen:draw({Cross(tx, ty, 8, 8), self.path})
      end
      if not self.image then return end
      if self.friendly then love.graphics.setColor(1, 1, 1)
      else love.graphics.setColor(1, 0, 0) end
      love.graphics.setLineWidth(.1)
      love.graphics.draw(self.image, self.quad, self.x, self.y, self.rot, self.scale, self.scale)
      love.graphics.rectangle('line', self.x, self.y, 8, 8)
      love.graphics.print(self.health, self.x, self.y-4, 0, .2, .2)
      if self.fire_target then
	 love.graphics.setColor(1, 0, 0)
	 love.graphics.line(self.x+4, self.y+4, self.fire_target[1]+4, self.fire_target[2]+4)
      end
      if self:is_hovered() and _lk.isDown("c") then 
	 love.graphics.setColor(.5, .5, .5)
	 love.graphics.circle('line', self.x+4, self.y+4, self.range)
	 love.graphics.setColor(.1, .1, .1)
	 love.graphics.circle('line', self.x+4, self.y+4, self.view_range)
      end
   end,
   
   is_hovered = function (self)
      local cx, cy = Game.cursor:get_position()
      if self.x == cx and self.y == cy then return true end
   end,
   
   request_path = function (self, x, y)
      return self.path:get_path_to(self.x, self.y, x, y)
   end,
   
   goto = function (self, x, y)
      self:request_path (x, y)
   end,
   
   tile_distance = function (self, x, y)
      return Game.grid:snap(lume.distance(self.x, self.y, x, y)/8)
   end,
   
   goto_near = function (self, x, y)
      local path = self:request_path (x, y)
      local tx, ty = path[2].x, path[2].y
      self.move_pos = {tx, ty}
   end,
   
   goto_atk_range = function (self, x, y)
      local path = self:request_path (self.x, self.y, x, y)
      local point = lume.match(path,
			       function (p)
				  return lume.distance(self.x, self.y, p.x *8, p.y*8) < self.range
      end)
   end,
   
   has_in_range = function (self, x, y)
      return lume.distance(self.x, self.y, x, y) <= self.range
   end,
   
   has_in_view = function (self, x, y)
      return lume.distance(self.x, self.y, x, y) <= self.view_range
   end,
   
   pick_target = function (self, x, y)
      self.fire_target = {x, y}
   end,
   
   fire_at = function (self, x, y)
      local a = Game:actor_on_position (x, y)
      if not a then return end
      self.can_fire = nil
      self.is_firing = true
      local result = lume.weightedchoice({["miss"] = 20, ["hit"] = 80}) 
      Timer.after(self.fire_cooldown, function () self.can_fire = true end):group(self.timers)
      if result == "hit" then
	 a.health = a.health - 8
      end
   end,
   
   think = function (self)
      self.thinking = true
      self.fire_target = nil
      lume.each(Game.actors,
		function (a)
		   if not a.visible then return end
		   if a == self or a.friendly and self.friendly or not a.friendly and not self.friendly then return end
		   if self:has_in_range(a.x, a.y) then
		      if not self.fire_target or lume.distance(self.x, self.y, a.x, a.y) < lume.distance(self.x, self.y, self.fire_target[1], self.fire_target[2]) then
			 self:pick_target (a.x, a.y)
		      end
		      if self.can_fire then self:fire_at(a.x, a.y) end
		   end
      end)
      if self.friendly then
	 lume.each(Game.actors,
		   function (a)
		      if a == self or a.friendly then return end
		      if self:has_in_view(a.x, a.y) then
			 a.visible = true
		      end
	 end)
      end
      local x, y = self.path:next_point ()
      if x and y and self.can_move then
	 self:move(x, y)
      end
   end,
   
   move = function (self, x, y)
      if x and y and self.can_move then
	 flux.to(self, self.speed, {x = x*8, y = y*8})
	    :oncomplete(function ()
		  self.can_move = true
		  self.path:advance ()
		       end)
	 self.can_move = false
      end
   end,

}
